package server;

import classLoader.MyClassLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import server.mapper.Service;
import utils.ProtocolHeaderUtil;
import utils.StaticResourceUtil;

import java.beans.XMLEncoder;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * miniCat的启动类
 */
public class BootStrap {
    /**
     * 端口号，TO_DO 改为读取配置
     */
    private Integer port =8080;
    int corePoolSize =10;
    int maximumPoolSize=50;
    long keepAliveTime=100;
    TimeUnit unit=TimeUnit.SECONDS;
    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
    ThreadFactory threadFactory = Executors.defaultThreadFactory();
    RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

    private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            unit,
            workQueue,
            threadFactory,
            handler);

    //---------------作业版本
    private  List<Service> serviceList = new ArrayList<>();

    //---------------作业版本

    //构建一个ServletMap
    private Map<String,Servlet> servletMap = new HashMap<>();

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    private void init() throws IOException, ClassNotFoundException, InstantiationException, DocumentException, IllegalAccessException {
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("====>>> lucas minicat start on port: "+port);
//        版本一:实现了简单直接反馈字符串
//        while(true){
//            Socket accept = serverSocket.accept();
//            OutputStream outputStream = accept.getOutputStream();
//            String text ="hello lucas minicat";
//            String reuslt = ProtocolHeaderUtil.getHeader200(Long.valueOf(text.length()))+text;
//            outputStream.write(reuslt.getBytes());
//            accept.close();
//        }
//      版本二:封装了request以及response,输出静态资源
//        while(true){
//            Socket accept = serverSocket.accept();
//            InputStream inputStream = accept.getInputStream();
//            OutputStream outputStream = accept.getOutputStream();
//            Request request = new Request(inputStream);
//            Response response = new Response(outputStream);
//            response.outputHtml(request.getUrl());
//
//            accept.close();
//        }

//       版本三:可以访问动态资源
//        while(true){
//            Socket socket = serverSocket.accept();
//            try {
//                //加载资源
//                loadConfig();
//
//                //封装response,request
//                Request request = new Request(socket.getInputStream());
//                Response response = new Response(socket.getOutputStream());
//
//                String url = request.getUrl();
//                if(servletMap.containsKey(url)){
//                    //有方法即调用servlet
//                    Servlet servlet = servletMap.get(url);
//                    servlet.service(request,response);
//                }else{
//                    response.outputHtml(url);
//                }
//
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//
//            socket.close();
//        }
//    }
//      版本四:使用多线程
//        while(true){
//            //加载资源
//            loadConfig();
//            Socket socket = serverSocket.accept();
//            ServletProcess servletProcess = new ServletProcess(servletMap,socket);
//            servletProcess.start();
//        }
        //    版本五:使用线程池
        while(true){
            //加载资源
            loadConfig();
            Socket socket = serverSocket.accept();
            ServletProcess servletProcess = new ServletProcess(servletMap,socket);
            poolExecutor.execute(servletProcess);
        }

        //版本六:使用webapps部署.
    }



    //读取配置
    private void loadWebConfig(String urlPath ,String path,String webAppName) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException, FileNotFoundException {

//        InputStream resourceAsStream = BootStrap.class.getClassLoader().getResourceAsStream(path);
        FileInputStream  resourceAsStream = new FileInputStream(new File(path));
        SAXReader saxReaer = new SAXReader();
        Document document = saxReaer.read(resourceAsStream);
        Element rootElement = document.getRootElement();//获取根节点

        List<Element> nodes = rootElement.selectNodes("//servlet");
        for (int i = 0; i < nodes.size(); i++) {
            Element element =  nodes.get(i);
            // <servlet-name>lagou</servlet-name>
            Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
            String servletName = servletnameElement.getStringValue();
            // <servlet-class>server.LagouServlet</servlet-class>
            Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
            String servletClass = servletclassElement.getStringValue();
            MyClassLoader classLoader = new MyClassLoader("D:\\Code\\lucas_tomcat_mini\\src\\main\\resources\\webapps\\"+webAppName+"\\classes\\","myclasscloderz");
            Class<?> aClass1 =  classLoader.findClass(servletClass);
            Object o = aClass1.newInstance();
            // 根据servlet-name的值找到url-pattern
            Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
            // /lagou
            String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
            urlPattern=urlPath+urlPattern;
            servletMap.put(urlPattern, (HttpServlet) o);

        }

    }
    //========>>作业模块 开始 属性
    private Service service;
    //========>>作业模块 结束 属性
    public void loadConfig() throws ClassNotFoundException, InstantiationException, DocumentException, IllegalAccessException, FileNotFoundException {
        //构建server配置
        this.loadServerConfig();
        String appBase = service.getConector().getHost().getAppBase();
        File file = new File(appBase);
        if(file.isDirectory()){
            File[] files = file.listFiles();
            String hostName = service.getConector().getHost().getName();
            String port =service.getConector().getPort();
            for (File file1 : files) {
                String name = file1.getName();
                String urlbase = "/"+name;
                String webXMLPath=file.getAbsolutePath()+"\\"+file1.getName()+"\\web.xml";
                String webappName =file1.getName();
                //构建web项目配置
                this.loadWebConfig(urlbase,webXMLPath,webappName);
            }
        }


    }

    public void loadServerConfig() throws DocumentException {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader reader = new SAXReader();
        Document document = reader.read(resourceAsStream);
        Element rootElement = document.getRootElement();//获取根标签

        List<Element> serviceList = rootElement.selectNodes("//Service");
        service = new Service(serviceList);
        System.out.println(service);
    }


    /**
     * miniCat程序入口
     * @param args
     */
    public static void main(String[] args) {
        BootStrap bootStrap = new BootStrap();
        try {
            bootStrap.init();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
